package com.wlyuan.open.domain.qrcode.service;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.alibaba.excel.util.StringUtils;
import com.wlyuan.core.exception.ValueError;
import com.wlyuan.open.domain.qrcode.QrCode;
import com.wlyuan.open.domain.qrcode.QrCodeDetail;
import com.wlyuan.open.infrastructure.config.OpenQrCodeProperties;
import com.wlyuan.upload.client.AliyunUploadClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.apache.commons.lang3.RandomStringUtils;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

/**
 * @author lijing
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class QrCodeService {
    private final AliyunUploadClient uploadClient;
    private final RedissonClient redissonClient;
    private final JsonJacksonCodec jsonJacksonCodec;
    private final OpenQrCodeProperties qrCodeProperties;
    private RMapCache<String, String> cacheMap;

    private static final String PATH = "pc/open/qrcode/%s.png";

    @PostConstruct
    public void initialize() {
        this.cacheMap = redissonClient.getMapCache("PC::CACHE::OPEN::QRCODE", jsonJacksonCodec);
        this.cacheMap.setMaxSize(1000);
    }

    /**
     * 生成二维码连接
     *
     * @param appId
     * @return
     */
    public QrCodeDetail generateQrCode(String appId) {
        var qrCodeDetail = getQrCodeDetail();
        var id = qrCodeDetail.getId();
        //前端页面地址与id
        var url = String.join("", qrCodeProperties.getUrl(), id);
        //二维码图片
        var image = QrCodeUtil.generate(url, getQrConfig());
        try {
            //上传到oss
            var result = uploadClient.upload(convert(image, "png"), getPath(id));
            //30分钟失效
            cacheMap.put(id, appId, qrCodeProperties.getTtl(), TimeUnit.MINUTES);
            qrCodeDetail.generate(result);
            return qrCodeDetail;
        } catch (Exception e) {
            logger.error("获取二维码失败：{}", e);
            throw new ValueError("获取二维码失败");
        }
    }

    private QrCodeDetail getQrCodeDetail() {
        return new QrCodeDetail(RandomStringUtils.randomAlphanumeric(16));
    }

    private QrConfig getQrConfig() {
        QrConfig qrConfig = new QrConfig();
        qrConfig.setWidth(qrCodeProperties.getWidth());
        qrConfig.setHeight(qrCodeProperties.getHeight());
        try {
            ClassPathResource resource = new ClassPathResource("img/logo.png");
            qrConfig.setImg(ImageIO.read(resource.getInputStream()));
        } catch (Exception e) {
            logger.error("生成二维码异常：{}", e);
        }
        return qrConfig;
    }

    private InputStream convert(BufferedImage image, String format) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, format, outputStream);
        return new ByteArrayInputStream(outputStream.toByteArray());
    }

    public String getQrCodeValue(String qrCodeId) {
        return cacheMap.get(qrCodeId);
    }

    /**
     * 校验二维码
     *
     * @param qrCodeId
     * @return
     */
    public QrCode check(String qrCodeId) {
        if (StringUtils.isBlank(qrCodeId)) {
            throw new ValueError("二维码不存在");
        }
        var appId = cacheMap.get(qrCodeId);
        //缓存失效
        if (appId == null) {
            //cacheMap.remove(qrCodeId);
            return new QrCode("").expire();
        }
        //被扫
        if (appId.isEmpty()) {
            //删除缓存
            //cacheMap.remove(qrCodeId);
            return new QrCode("").scanner();
        }
        //没有扫描
        return new QrCode(appId).noScanner();
    }

    /**
     * 删除文件
     *
     * @param qrCodeId
     */
    public void remove(String qrCodeId) {
        uploadClient.delete(getPath(qrCodeId));
    }

    public void scanner(String qrCodeId) {
        cacheMap.put(qrCodeId, "");
    }

    private String getPath(String id) {
        return String.format(PATH, id);
    }
}
